#define WITH_FS_RES

#include <awtk.h>
#include <awtk_main.inc>

#include "demo_ui.h"
#include "../res/assets.inc"

#define THEME_NAME_PREFIX               "uiex_"
#define WINDOW_NAME_PREFIX              "uiex/"

#define APP_DEFAULT_LANGUAGE            "zh"

#define PRELOAD_DURATION                2000        /* 预加载窗口显示时长（单位：毫秒） */
#define ENABLE_PAGE_SWITCH              1           /* 是否开启滚动切换页面功能 */

#define PAGE_NUM                        18
#if !defined(PAGE_NUM) || (PAGE_NUM <= 0)
#error "PAGE_NUM not define or less than or equal to zero!"
#endif

#define LANDSCAPE_WIDTH_THRESHOLD       540         /* 横屏窗口阈值 */

#define PRELOAD_NAME                    "preload"

#ifdef WITH_FS_RES
#ifndef APP_DEFAULT_FONT
#define APP_DEFAULT_FONT                "default_full"
#endif
#endif

#define DIALOG_INFO_THEME               THEME_NAME_PREFIX "dialog_info"
#define DIALOG_WARN_THEME               THEME_NAME_PREFIX "dialog_warn"
#define DIALOG_CONFIRM_THEME            THEME_NAME_PREFIX "dialog_confirm"

#define MENU_BAR_NAME                   "menu_bar"

#define CHAT_BUBBLE_ADD_CHAR_INTERVAL   150         /* 聊天气泡添加字符时间（毫秒）间隔 */

#if defined(ENABLE_PAGE_SWITCH) && ENABLE_PAGE_SWITCH
#define PAGE_SWITCH_THRESHOLD           100
#define PAGE_SWITCH_PROP_ENABLE         "page_switch_enable"
#endif

#define WIDGET_PROP_DISABLE_IN_1M       "disable_in_1m"
#define WIDGET_PROP_INVISIBLE_IN_1M     "invisible_in_1m"

static bool_t s_is_portrait = TRUE;
static bool_t s_is_full_font = FALSE;
static uint32_t s_win_default_width = 320;
static uint32_t s_win_default_height = 480;
static bool_t s_win_default_portrait = TRUE;
static char s_page_name[TK_NAME_LEN + 1] = {0};
static const char *s_win_name = "menu_${device_orientation}";
static const char *s_sysbar_name = "sysbar_${device_orientation}";

static uint32_t s_chat_bubble_len = 1;
static const char *s_chat_bubble = " ";
static char s_chat_bubble_origin[64] = "";
static uint32_t s_chat_bubble_curr_len = 0;

typedef ret_t (*page_enter_func_t)(widget_t *page);

static page_enter_func_t s_page_enter_func_array[PAGE_NUM] = {NULL};
static const char *preload_info[] = {"Time init...", "Memory init...", "System info init...", "Reource to load..."};

static ret_t set_win_name(void);
static bool_t get_portrait(uint32_t w, int32_t h);
static ret_t common_init_widget(void *ctx, const void *iter);
static void init_children_widget(widget_t *widget, void *ctx);
static ret_t on_adject_vpage_in_1m_assets(void *ctx, event_t *e);

static ret_t change_language(bool_t is_chinese)
{
    ret_t ret = RET_FAIL;
    const char *country = is_chinese ? "CN" : "US";
    const char *language = is_chinese ? "zh" : "en";

    if (strcmp(locale_info()->country, country) || strcmp(locale_info()->language, language)) {
        ret = locale_info_change(locale_info(), language, country);
    } else {
        event_t e = event_init(EVT_LOCALE_CHANGED, locale_info());
        ret = locale_info_reload(locale_info());
        emitter_dispatch(locale_info()->emitter, &e);
    }

    return ret;
}

static ret_t on_language_changed(void *ctx, event_t *e)
{
    value_change_event_t *evt = value_change_event_cast(e);
    return change_language(value_bool(&(evt->new_value)));
}

static ret_t change_theme(bool_t is_dark)
{
    return assets_set_global_theme(is_dark ? "dark" : "default");
}

static color_t get_bg_color(void)
{
    bool_t is_dark = tk_str_eq(assets_manager()->theme, "dark");
    color_t ret = is_dark ? color_init(0x26, 0x26, 0x26, 0xff) : color_init(0xf7, 0xf7, 0xf7, 0xff);
    return ret;
}

static ret_t on_change_theme(void *ctx, event_t *e)
{
    value_change_event_t *evt = value_change_event_cast(e);
    return change_theme(value_bool(&(evt->new_value)));
}

// 点击对话框外，退出对话框
static ret_t on_dialog_quit(void *ctx, event_t *e)
{
    widget_t *dialog_win = (widget_t *)ctx;
    widget_t *wm = window_manager();
    dialog_t *dialog = DIALOG(dialog_win);
    pointer_event_t *evt = (pointer_event_t *)e;
    rect_t dialog_r = {dialog_win->x, dialog_win->y, dialog_win->w, dialog_win->h};
    rect_t wm_r = {wm->x, wm->y, wm->w, wm->h};

    return_value_if_fail(dialog != NULL && evt != NULL, RET_BAD_PARAMS);

    if (rect_contains(&wm_r, evt->x, evt->y) && !rect_contains(&dialog_r, evt->x, evt->y)) {
        return dialog->is_model ? dialog_quit(dialog_win, DIALOG_QUIT_CANCEL) : window_close(dialog_win);
    }

    return RET_OK;
}

static widget_t *window_open_with_prefix(const char *name)
{
    char name_with_prefix[TK_NAME_LEN + 1] = {0};

    tk_snprintf(name_with_prefix, ARRAY_SIZE(name_with_prefix), "%s%s", WINDOW_NAME_PREFIX, name);
    return window_open(name_with_prefix);
}

static ret_t on_quit(void *ctx, event_t *e)
{
    ret_t ret = dialog_simple_show("Confirm", "Do you really want to exit?", DIALOG_CONFIRM_THEME, TRUE, TRUE);
    if (RET_OK == ret) {
        return tk_quit();
    }

    return RET_OK;
}

static ret_t on_close_window(void *ctx, event_t *e)
{
    widget_t *win = WIDGET(ctx);
    return window_close(win);
}

static const char *get_name(const char *path)
{
    uint32_t i = 0;
    uint32_t j = 0;
    const char *name = path;

    for (; path[i] != '\0'; i++) {
        if (path[i] == '\\' || path[i] == '/') {
            j = i;
        }
    }

    if (j != 0) {
        name = path + j + 1;
    }

    return name;
}

static ret_t on_open_window(void *ctx, event_t *e)
{
  const char *path = (const char *)ctx;
  const char *name = get_name(path);

    if (tk_str_eq(name, "toast")) {
        dialog_toast("Hello! AWTK.", 2000);
    } else if (tk_str_eq(name, "info")) {
        dialog_simple_show("info", "Hello! AWTK.", DIALOG_INFO_THEME, TRUE, FALSE);
    } else if (tk_str_eq(name, "warn")) {
        dialog_simple_show("Warning", "Not sufficient funds!", DIALOG_WARN_THEME, TRUE, FALSE);
    } else if (tk_str_eq(name, "confirm")) {
        dialog_simple_show("Confirm", "Are you ready?", DIALOG_CONFIRM_THEME, TRUE, TRUE);
    } else {
        widget_t *target = widget_lookup(window_manager(), name, TRUE);

        if (target != NULL) {
            widget_t *win = widget_get_window(WIDGET(e->target));
            window_manager_switch_to(window_manager(), win, target, FALSE);
        } else {
            widget_t *win = window_open(path);
            widget_foreach(win, common_init_widget, NULL);
        }
    }

    (void)e;
    return RET_OK;
}

static ret_t on_open_or_close_window(void *ctx, event_t *e)
{
    ret_t ret = RET_FAIL;
    widget_t *widget = NULL;

    return_value_if_fail(e != NULL, RET_BAD_PARAMS);

    widget = WIDGET(e->target);
    return_value_if_fail(widget != NULL, RET_BAD_PARAMS);

    if (widget_get_value(widget)) {
        ret = on_open_window(ctx, e);
    } else {
        const char *path = (const char*)ctx;
        const char *name = get_name(path);
        widget_t *win = widget_lookup(window_manager(), name, FALSE);

        ret = on_close_window((void *)win, e);
    }

    return ret;
}

// scroll_view中含有pages时，由于 widget_ensure_visible_in_viewport()函数的作用，需要用此函数将scroll_view重新滚动到最顶
static ret_t on_scroll_to_top(const idle_info_t *idle)
{
    widget_t *scroll_view = WIDGET(idle->ctx);
    return_value_if_fail(scroll_view != NULL, RET_BAD_PARAMS);

    scroll_view_set_offset(scroll_view, 0, 0);
    return RET_REMOVE;
}

static widget_t *find_bind_value_target(widget_t *widget, const char *name)
{
    widget_t *target = NULL;
    return_value_if_fail(widget != NULL && name != NULL, NULL);

    if (tk_str_start_with(name, "bind_value:")) {
        tokenizer_t t;
        const char *subname = NULL;
        widget_t *parent = widget->parent;

        name += 11;
        tokenizer_init(&t, name, tk_strlen(name), "/");

        while ((subname = tokenizer_next(&t)) != NULL) {
            if (tokenizer_has_more(&t)) {
                if (tk_str_eq(subname, "..")) {
                    parent = parent->parent;
                } else {
                    while (parent != NULL) {
                        widget_t *tmp = widget_lookup(parent, subname, FALSE);
                        if (tmp != NULL) {
                            parent = tmp;
                            break;
                        } else {
                            parent = parent->parent;
                        }
                    }
                }
            } else {
                target = widget_lookup(parent, subname, FALSE);
            }
        }

        tokenizer_deinit(&t);
    }

    return target;
}

static ret_t on_bind_value_changed(void *ctx, event_t *e)
{
    char prop_name[16] = {0};
    widget_t *widget = WIDGET(ctx);
    widget_t *target = WIDGET(e->target);

    return_value_if_fail(widget != NULL && target != NULL, RET_BAD_PARAMS);

    tk_snprintf(prop_name, sizeof(prop_name), "%s%s", WIDGET_PROP_ANIMATE_PREFIX, WIDGET_PROP_VALUE);
    return widget_set_prop_float(widget, prop_name, widget_get_value(target));
}

static ret_t common_init_widget(void *ctx, const void *iter)
{
    (void)ctx;

    widget_t *widget = WIDGET(iter);
    widget_t *win = widget_get_window(widget);

    if (widget->name != NULL) {
        const char *name = widget->name;

        if (strstr(name, "open:") != NULL) {
            const char *type = widget_get_type(widget);
            if (tk_str_eq(type, WIDGET_TYPE_BUTTON)) {
                widget_on(widget, EVT_CLICK, on_open_window, (void *)(name + 5));
                widget_on(widget, EVT_LONG_PRESS, on_open_window, (void *)(name + 5));
            } else if (tk_str_eq(type, WIDGET_TYPE_CHECK_BUTTON)) {
                const char *true_name = get_name(name + 5);
                widget_set_value(widget, widget_lookup(window_manager(), true_name, FALSE) != NULL);
                widget_on(widget, EVT_VALUE_CHANGED, on_open_or_close_window, (void *)(name + 5));
            }
        } else if (tk_str_eq(name, "close()")) {
            widget_on(widget, EVT_POINTER_UP, on_close_window, win);
        } else if (tk_str_eq(name, "quit()")) {
            widget_on(widget, EVT_POINTER_UP, on_quit, NULL);
        } else if (tk_str_start_with(name, "bind_value:")) {
            widget_t *target = find_bind_value_target(widget, name);
            widget_on(target, EVT_VALUE_CHANGED, on_bind_value_changed, (void *)widget);
        }
    }

    return RET_OK;
}

static ret_t on_page_change(void *ctx, event_t *e)
{
    ret_t ret = RET_FAIL;
    widget_t *pages = WIDGET(ctx);

    widget_off_by_func(widget_get_window(pages), EVT_WINDOW_TO_FOREGROUND, on_page_change, pages);
    ret = pages_set_active_by_name(pages, s_page_name);
    memset(s_page_name, 0, ARRAY_SIZE(s_page_name));

    return ret;
}

static ret_t on_tb_value_changed(void *ctx, event_t *e)
{
    widget_t *tb = WIDGET(e->target);
    widget_t *pages = WIDGET(ctx);
    widget_t *dialog_win = widget_get_window(tb);
    dialog_t *dialog = DIALOG(dialog_win);

    return_value_if_fail(tb != NULL && pages != NULL && dialog != NULL, RET_BAD_PARAMS);

    if (widget_get_value(tb)) {
        tk_snprintf(s_page_name, ARRAY_SIZE(s_page_name), "page_%s", tb->name + 3);
        widget_on(widget_get_window(pages), EVT_WINDOW_TO_FOREGROUND, on_page_change, pages);

        return dialog->is_model ? dialog_quit(dialog_win, DIALOG_QUIT_OK) : window_close(dialog_win);
    }

    return RET_OK;
}

static ret_t menu_bar_init_widget(void *ctx, const void *iter)
{
    widget_t *widget = WIDGET(iter);
    pages_t *pages = PAGES(ctx);

    if (widget->name != NULL) {
        const char *name = widget->name;

        if (tk_str_eq(name, "view_menu")) {
            uint32_t j = 0;

            WIDGET_FOR_EACH_CHILD_BEGIN(widget, tb, i)
            const char *type = widget_get_type(tb);
            if (tk_str_eq(type, WIDGET_TYPE_TAB_BUTTON)) {
                if (pages->active == j++) {
                    widget_set_value(tb, TRUE);
                }
            }
            WIDGET_FOR_EACH_CHILD_END()

            WIDGET_FOR_EACH_CHILD_BEGIN(widget, tb, i)
            const char *type = widget_get_type(tb);
            if (tk_str_eq(type, WIDGET_TYPE_TAB_BUTTON)) {
                widget_on(tb, EVT_VALUE_CHANGED, on_tb_value_changed, &pages->widget);
            }
            WIDGET_FOR_EACH_CHILD_END()
        } else if (tk_str_eq(name, "rb_dark")) {
            widget_set_value(widget, tk_str_eq(assets_manager()->theme, "dark"));
            widget_on(widget, EVT_VALUE_CHANGED, on_change_theme, NULL);
        } else if (tk_str_eq(name, "rb_zh")) {
            if (s_is_full_font) {
                widget_set_value(widget, tk_str_eq(locale_info()->language, "zh"));
                widget_on(widget, EVT_VALUE_CHANGED, on_language_changed, NULL);
            } else {
                widget_set_value(widget, FALSE);
                widget_set_enable(widget->parent, FALSE);
            }
        }
    }

    return RET_OK;
}

static ret_t on_menu_bar_move_resize(void *ctx, event_t *e)
{
    widget_t *menu_bar = WIDGET(e->target);
    return widget_move_resize(menu_bar, 0, 0, menu_bar->w, window_manager()->h);
}

static ret_t open_menu_bar(widget_t *pages)
{
    widget_t *dialog = widget_lookup(window_manager(), MENU_BAR_NAME, FALSE);
    if (dialog != NULL) {
        return RET_SKIP;
    }

    widget_set_as_key_target(pages);
    dialog = window_open_with_prefix(MENU_BAR_NAME);

    return_value_if_fail(dialog != NULL, RET_BAD_PARAMS);

    widget_foreach(dialog, menu_bar_init_widget, pages);
    widget_on(dialog, EVT_POINTER_UP, on_dialog_quit, dialog);
    widget_on(dialog, EVT_MOVE_RESIZE, on_menu_bar_move_resize, NULL);
    dialog_modal(dialog);

    return RET_OK;
}

static ret_t on_fps_visable(void *ctx, event_t *e)
{
    value_change_event_t *vce = value_change_event_cast(e);
    return_value_if_fail(vce != NULL, RET_BAD_PARAMS);

    window_manager_set_show_fps(window_manager(), value_bool(&vce->new_value));
    widget_invalidate_force(window_manager(), NULL);

    return RET_OK;
}

static ret_t on_switch_ratio(void *ctx, event_t *e)
{
    (void)s_is_portrait, (void)s_win_default_portrait;
    (void)s_win_default_width, (void)s_win_default_height;
    dialog_toast("Embedded system not support switch ratio!", 2000);

    return RET_OK;
}

static ret_t page_button_init(widget_t *page)
{
    widget_t *cb_fps = NULL;
    widget_t *cb_ratio = NULL;

    return_value_if_fail(page != NULL, RET_BAD_PARAMS);

    cb_fps = widget_lookup(page, "cb_fps", TRUE);
    cb_ratio = widget_lookup(page, "cb_ratio", TRUE);
    if (cb_fps != NULL && tk_str_eq(widget_get_type(cb_fps), WIDGET_TYPE_CHECK_BUTTON)) {
        widget_set_value(cb_fps, WINDOW_MANAGER(window_manager())->show_fps);
        widget_on(cb_fps, EVT_VALUE_CHANGED, on_fps_visable, NULL);
    }

    if (cb_ratio != NULL) {
        widget_on(cb_ratio, EVT_CLICK, on_switch_ratio, NULL);
    }

    return widget_foreach(page, common_init_widget, NULL);
}

static ret_t page_slider_init(widget_t *page)
{
    return_value_if_fail(page != NULL, RET_BAD_PARAMS);
    return widget_foreach(page, common_init_widget, NULL);
}

static ret_t add_char_to_chat_bubble(const timer_info_t *timer)
{
    wstr_t str;
    widget_t *lb_chat_bubble = (widget_t *)timer->ctx;

    return_value_if_fail(lb_chat_bubble != NULL, RET_REMOVE);

    wstr_init(&str, s_chat_bubble_curr_len);
    if (s_chat_bubble_curr_len > 0) {
        wstr_set_utf8_with_len(&str, s_chat_bubble, s_chat_bubble_curr_len);
    } else {
        wstr_set_utf8(&str, " ");
    }
    widget_set_text(lb_chat_bubble, str.str);
    wstr_reset(&str);

    s_chat_bubble_curr_len = (s_chat_bubble_curr_len + 1) % (s_chat_bubble_len + 1);

    return RET_REPEAT;
}

static ret_t change_chat_content(widget_t *chat_bubble)
{
    s_chat_bubble = locale_info_tr(widget_get_locale_info(chat_bubble), s_chat_bubble_origin);
    s_chat_bubble_len = tk_strlen(s_chat_bubble);

    if (s_chat_bubble_curr_len > s_chat_bubble_len - 1) {
        s_chat_bubble_curr_len = s_chat_bubble_len - 1;
    }

    return RET_OK;
}

static ret_t on_change_chat_content(void *ctx, event_t *e)
{
    widget_t *lb_chat_bubble = WIDGET(ctx);
    return change_chat_content(lb_chat_bubble);
}

static ret_t on_chat_bubble_destroy(void *ctx, event_t *e)
{
    widget_t *lb_chat_bubble = WIDGET(e->target);
    widget_t *win = WIDGET(ctx);

    return widget_off_by_func(win, EVT_LOCALE_CHANGED, on_change_chat_content, (void *)lb_chat_bubble);
}

static ret_t page_image_init(widget_t *page)
{
    widget_t *lb_chat_bubble = NULL;
    widget_t *scroll_view_to_top = NULL;

    return_value_if_fail(page != NULL, RET_BAD_PARAMS);

    lb_chat_bubble = widget_lookup(page, "lb_chat_bubble", TRUE);
    if (lb_chat_bubble != NULL && widget_get_visible(lb_chat_bubble)) {
        widget_t *win = widget_get_window(lb_chat_bubble);
        widget_get_text_utf8(lb_chat_bubble, s_chat_bubble_origin, ARRAY_SIZE(s_chat_bubble_origin));
        change_chat_content(lb_chat_bubble);

        widget_on(win, EVT_LOCALE_CHANGED, on_change_chat_content, (void *)lb_chat_bubble);
        widget_on(lb_chat_bubble, EVT_DESTROY, on_chat_bubble_destroy, (void *)win);
        widget_add_timer(lb_chat_bubble, add_char_to_chat_bubble, CHAT_BUBBLE_ADD_CHAR_INTERVAL);
    }

    scroll_view_to_top = widget_lookup(page, "scroll_view_to_top", TRUE);
    if (scroll_view_to_top != NULL &&
        tk_str_eq(widget_get_type(scroll_view_to_top), WIDGET_TYPE_SCROLL_VIEW)) {
        widget_add_idle(scroll_view_to_top, on_scroll_to_top);
    }

    return RET_OK;
}

static ret_t page_tab_ctrl_init(widget_t *page)
{
    widget_t *scroll_view_to_top = NULL;
    return_value_if_fail(page != NULL, RET_BAD_PARAMS);

    scroll_view_to_top = widget_lookup(page, "scroll_view_to_top", TRUE);
    if (scroll_view_to_top != NULL && tk_str_eq(widget_get_type(scroll_view_to_top), WIDGET_TYPE_SCROLL_VIEW)) {
        widget_add_idle(scroll_view_to_top, on_scroll_to_top);
    }

    return RET_OK;
}

static ret_t on_paint_linear_gradient(void *ctx, event_t *e)
{
    paint_event_t *evt = paint_event_cast(e);
    canvas_t *c = evt->c;
    widget_t *widget = WIDGET(e->target);
    vgcanvas_t *vg = canvas_get_vgcanvas(c);
    color_t scolor = color_init(0x82, 0xb4, 0x43, 0xff);
    color_t ecolor = get_bg_color();
    rect_t r = rect_init(0, 0, widget->w, widget->h);

    vgcanvas_save(vg);
    vgcanvas_translate(vg, c->ox, c->oy);

    vgcanvas_rect(vg, r.x, r.y, r.w, r.h);
    vgcanvas_set_fill_linear_gradient(vg, r.x, r.y, r.x + r.w, r.y, scolor, ecolor);
    vgcanvas_fill(vg);

    vgcanvas_restore(vg);

    return RET_OK;
}

static ret_t on_paint_radial_gradient(void *ctx, event_t *e)
{
    paint_event_t *evt = paint_event_cast(e);
    canvas_t *c = evt->c;
    widget_t *widget = WIDGET(e->target);
    vgcanvas_t *vg = canvas_get_vgcanvas(c);
    color_t scolor = color_init(0x82, 0xb4, 0x43, 0xff);
    color_t ecolor = get_bg_color();
    rect_t r = rect_init(0, 0, widget->w, widget->h);
    uint32_t radial = tk_max(r.w, r.h) / 2;

    vgcanvas_save(vg);
    vgcanvas_translate(vg, c->ox, c->oy);

    vgcanvas_rect(vg, r.x, r.y, r.w, r.h);
    vgcanvas_set_fill_radial_gradient(vg, r.x + r.w / 2, r.y + r.h / 2, 0, radial, scolor, ecolor);
    vgcanvas_fill(vg);

    vgcanvas_restore(vg);

    return RET_OK;
}

static ret_t on_paint_stroke_gradient(void *ctx, event_t *e)
{
    paint_event_t *evt = paint_event_cast(e);
    canvas_t *c = evt->c;
    widget_t *widget = WIDGET(e->target);
    vgcanvas_t *vg = canvas_get_vgcanvas(c);
    color_t scolor = color_init(0xd8, 0xd4, 0, 0xff);
    color_t ecolor = color_init(0x19, 0xa9, 0xeb, 0xff);
    uint32_t r = tk_min(widget->w, widget->h) / 3;

    vgcanvas_save(vg);
    vgcanvas_translate(vg, c->ox, c->oy);
    vgcanvas_set_stroke_linear_gradient(vg, 0, 0, widget->w, widget->h, scolor, ecolor);

    vgcanvas_move_to(vg, 10, widget->h / 4);
    vgcanvas_set_line_width(vg, 5);

    vgcanvas_line_to(vg, widget->w / 2, widget->h);
    vgcanvas_line_to(vg, widget->w / 2, 0);
    vgcanvas_line_to(vg, widget->w - 10, widget->h * 3 / 4);
    vgcanvas_stroke(vg);

    vgcanvas_begin_path(vg);
    vgcanvas_arc(vg, widget->w / 2, widget->h / 2, r, 0, M_PI * 2, FALSE);
    vgcanvas_stroke(vg);

    vgcanvas_restore(vg);

    return RET_OK;
}

static ret_t page_color_init_widget(void *ctx, const void *iter)
{
    (void)ctx;
    widget_t *widget = WIDGET(iter);

    if (widget->name != NULL) {
        const char *name = widget->name;

        if (tk_str_eq(name, "paint_linear_gradient")) {
            widget_on(widget, EVT_PAINT, on_paint_linear_gradient, NULL);
        } else if (tk_str_eq(name, "paint_radial_gradient")) {
            widget_on(widget, EVT_PAINT, on_paint_radial_gradient, NULL);
        } else if (tk_str_eq(name, "paint_stroke_gradient")) {
            widget_on(widget, EVT_PAINT, on_paint_stroke_gradient, NULL);
        }
    }

    return RET_OK;
}

static ret_t page_color_init(widget_t *page)
{
    return_value_if_fail(page != NULL, RET_BAD_PARAMS);
    return widget_foreach(page, page_color_init_widget, NULL);
}

static ret_t page_animate_init(widget_t *page)
{
    return_value_if_fail(page != NULL, RET_BAD_PARAMS);
    return widget_foreach(page, common_init_widget, NULL);
}

static ret_t paint_line_chart(void *ctx, event_t *e)
{
    paint_event_t *evt = paint_event_cast(e);
    canvas_t *c = evt->c;
    widget_t *widget = WIDGET(e->target);
    vgcanvas_t *vg = canvas_get_vgcanvas(c);
    color_t color_point = color_init(0x70, 0x99, 0x18, 0xff);
    color_t color_point_bg = get_bg_color();
    color_t color_line = color_init(0x70, 0x99, 0x18, 0xff);
    color_t color_axis = color_init(0x80, 0x80, 0x80, 0xff);
    const int32_t x_div_part = 10;
    const int32_t y_div_part = 5;
    const int32_t x_axis_offset = 20;
    const int32_t y_axis_offset = 50;
    const int32_t x_axis_end_sep = 20;
    const int32_t y_axis_end_sep = 10;
    point_t x_asis_p = {tk_max(y_axis_offset - 6, 0), widget->h - x_axis_offset};
    point_t y_asis_p = {y_axis_offset, y_axis_end_sep};
    int32_t x_axis_len = widget->w - x_asis_p.x - x_axis_end_sep;
    int32_t y_axis_len = widget->h - y_asis_p.y - tk_max(x_axis_offset - 6, 0);
    point_t org_p = {y_axis_offset, widget->h - x_axis_offset};
    const point_t data_p[11] = {{0, 0}, {1, 10}, {2, 30}, {3, 20}, {4, 40}, {5, 10}, {6, 0}, {7, 20}, {8, 40}, {9, 30}, {10, 50}};
    point_t tr_point[11] = {{0, 0}};
    point_t tmp_p;
    int32_t i = 0;

    vgcanvas_save(vg);

    canvas_set_stroke_color(c, color_axis);
    canvas_draw_hline(c, x_asis_p.x, x_asis_p.y, x_axis_len);
    canvas_draw_vline(c, y_asis_p.x, y_asis_p.y, y_axis_len);

    canvas_set_font(c, "default", 20);
    canvas_set_text_color(c, color_axis);
    canvas_set_text_align(c, ALIGN_H_CENTER, ALIGN_V_MIDDLE);

    x_axis_len -= 15;
    y_axis_len -= 15;

    for (tmp_p = org_p; tmp_p.x <= org_p.x + x_axis_len; tmp_p.x += x_axis_len / x_div_part) {
        rect_t r;
        wstr_t lb_str;

        wstr_init(&lb_str, 0);
        wstr_from_int(&lb_str, i++);
        r = rect_init(tmp_p.x - (c->font_size * lb_str.size / 2), tmp_p.y + 6, c->font_size * lb_str.size, c->font_size);
        canvas_draw_text_in_rect(c, lb_str.str, lb_str.size, &r);
        wstr_reset(&lb_str);
        canvas_draw_vline(c, tmp_p.x - (c->font_size * lb_str.size / 2), tmp_p.y, 6);
    }

    canvas_set_text_align(c, ALIGN_H_LEFT, ALIGN_V_MIDDLE);
    i = 0;

    for (tmp_p = org_p; tmp_p.y >= org_p.y - y_axis_len; tmp_p.y -= y_axis_len / y_div_part) {
        if (i != 0) {
            rect_t r;
            wstr_t lb_str;

            wstr_init(&lb_str, 0);
            wstr_from_int(&lb_str, i);
            r = rect_init(tmp_p.x - 6 - tk_max(c->font_size * (lb_str.size - 1), 0), tmp_p.y - c->font_size / 2, c->font_size * lb_str.size, c->font_size);
            canvas_draw_text_in_rect(c, lb_str.str, lb_str.size, &r);
            wstr_reset(&lb_str);
            canvas_draw_hline(c, tmp_p.x - 6, tmp_p.y, 6);
        }

        i += 10;
    }

    vgcanvas_translate(vg, c->ox, c->oy);
    vgcanvas_begin_path(vg);
    vgcanvas_set_line_width(vg, 2);
    vgcanvas_set_stroke_color(vg, color_line);

    for (i = 0; i < ARRAY_SIZE(data_p); i++) {
        tr_point[i].x = y_axis_offset + x_axis_len * data_p[i].x / x_div_part;
        tr_point[i].y = widget->h - (x_axis_offset + y_axis_len * data_p[i].y / (y_div_part * 10));

        if (i == 0) {
            vgcanvas_move_to(vg, tr_point[i].x, tr_point[i].y);
        } else {
            vgcanvas_line_to(vg, tr_point[i].x, tr_point[i].y);
        }
    }
    vgcanvas_stroke(vg);

    vgcanvas_set_fill_color(vg, color_point);
    for (i = 0; i < ARRAY_SIZE(tr_point); i++) {
        vgcanvas_ellipse(vg, tr_point[i].x, tr_point[i].y, 4, 4);
        vgcanvas_fill(vg);
    }

    vgcanvas_set_fill_color(vg, color_point_bg);
    for (i = 0; i < ARRAY_SIZE(tr_point); i++) {
        vgcanvas_ellipse(vg, tr_point[i].x, tr_point[i].y, 2, 2);
        vgcanvas_fill(vg);
    }

    vgcanvas_restore(vg);

    return RET_OK;
}

static ret_t page_chart_init_widget(void *ctx, const void *iter)
{
    (void)ctx;
    widget_t *widget = WIDGET(iter);

    if (widget->name != NULL) {
        const char *name = widget->name;

        if (tk_str_eq(name, "paint_line_chart")) {
            widget_on(widget, EVT_PAINT, paint_line_chart, NULL);
        }
    }

    return RET_OK;
}

static ret_t page_chart_init(widget_t *page)
{
    return_value_if_fail(page != NULL, RET_BAD_PARAMS);
    return widget_foreach(page, page_chart_init_widget, NULL);
}

static ret_t page_window_init(widget_t *page)
{
    return_value_if_fail(page != NULL, RET_BAD_PARAMS);
    return widget_foreach(page, common_init_widget, NULL);
}

static ret_t fix_widget_size(void *ctx, const void *iter)
{
    widget_t *widget = WIDGET(iter);
    widget_t *root = WIDGET(ctx);
    widget_t *parent = widget->parent;

    if (widget == root) {
        return RET_OK;
    }

    if (widget->x + widget->w > root->w) {
        while (parent != NULL) {
            scroll_view_t *sv_parent = (scroll_view_t*)parent;

            if (tk_str_eq(WIDGET_TYPE_SCROLL_VIEW, widget_get_type(parent)) && sv_parent->xslidable) {
                break;
            }

            parent = parent->parent;
        }

        if (parent == NULL) {
            widget_resize(widget, root->w - widget->x - 20, widget->h);
        }
    } else if (tk_str_eq(WIDGET_TYPE_GRID, widget_get_type(widget)) || tk_str_eq(WIDGET_TYPE_ROW, widget_get_type(widget))) {
        bool_t want_to_fix = FALSE;

        if (widget->w != 0) {
            WIDGET_FOR_EACH_CHILD_BEGIN(widget, child, i)
            if (child->w == 0 || child->h == 0) {
                want_to_fix = TRUE;
            }
            WIDGET_FOR_EACH_CHILD_END()
        }

        if (want_to_fix) {
            value_t v;
            uint32_t visible_children_num = 0;
            uint8_t x_margin, y_margin, spacing = 0;
            uint16_t real_w, real_h, real_row, w, h = 0;

            WIDGET_FOR_EACH_CHILD_BEGIN(widget, child, i)
            if (widget_get_visible(child)) {
                visible_children_num++;
            }
            WIDGET_FOR_EACH_CHILD_END()

            children_layouter_get_param(widget->children_layout, "w", &v);
            w = value_uint16(&v);
            children_layouter_get_param(widget->children_layout, "h", &v);
            h = value_uint16(&v);
            children_layouter_get_param(widget->children_layout, "x", &v);
            x_margin = value_uint8(&v);
            children_layouter_get_param(widget->children_layout, "y", &v);
            y_margin = value_uint8(&v);
            children_layouter_get_param(widget->children_layout, "s", &v);
            spacing = value_uint8(&v);

            real_w = 2 * x_margin + tk_max((int32_t)((w + spacing) * visible_children_num - spacing), 0);

            real_row = tk_min(visible_children_num, tk_roundi(tk_max((1.0 * real_w / widget->w) + 0.5 * ((real_w % widget->w) != 0), 1)));
            real_h = 2 * y_margin + real_row * (h + spacing) - spacing;

            if (tk_str_eq(WIDGET_TYPE_GRID, widget_get_type(widget->parent)) || tk_str_eq(WIDGET_TYPE_ROW, widget_get_type(widget->parent))) {
                widget_resize(widget->parent, widget->parent->w, widget->parent->h + real_h - widget->h);
            }

            widget_resize(widget, root->w, real_h);
        }
    }

    return RET_OK;
}

static ret_t change_menu_title(widget_t *win, widget_t *page)
{
    widget_t *menu_ti = widget_lookup(win, "lb_menu_ti", TRUE);
    return_value_if_fail(menu_ti != NULL && page != NULL, RET_BAD_PARAMS);

    return widget_set_tr_text(menu_ti, page->tr_text);
}

#if defined(ENABLE_PAGE_SWITCH) && ENABLE_PAGE_SWITCH
static ret_t on_page_switch_before(void *ctx, event_t *e)
{
    int32_t y = 0;
    int32_t index = -1;
    int32_t move_dy = 0;
    widget_t *page = WIDGET(ctx);
    scroll_view_t *scroll_view = NULL;
    pointer_event_t *pe = (pointer_event_t *)e;

    return_value_if_fail(page != NULL && pe != NULL, RET_BAD_PARAMS);

    scroll_view = SCROLL_VIEW(widget_lookup_by_type(page, WIDGET_TYPE_SCROLL_VIEW, TRUE));
    return_value_if_fail(scroll_view != NULL, RET_BAD_PARAMS);

    index = widget_index_of(page);

    move_dy = scroll_view->down.y - pe->y;
    y = scroll_view->yoffset_save + move_dy;

    if (scroll_view->pressed && ((0 < index && y < -PAGE_SWITCH_THRESHOLD) || (index < PAGE_NUM - 1 && y + scroll_view->widget.h > scroll_view->virtual_h + PAGE_SWITCH_THRESHOLD))) {
        scroll_view->pressed = FALSE;
        widget_set_prop_bool(&scroll_view->widget, PAGE_SWITCH_PROP_ENABLE, TRUE);
    }

    return RET_OK;
}

static ret_t on_page_switch(void *ctx, event_t *e)
{
    int32_t y = 0;
    widget_t *page = WIDGET(ctx);
    widget_t *win = NULL;
    widget_t *pages = NULL;
    widget_t *view_menu = NULL;
    scroll_view_t *scroll_view = SCROLL_VIEW(e->target);
    pointer_event_t *pe = (pointer_event_t *)e;
    int32_t move_dy = 0;
    ret_t ret = RET_SKIP;
    int32_t old_index = -1;
    int32_t new_index = -1;
    bool_t switch_enable = FALSE;
    return_value_if_fail(page != NULL && pe != NULL && scroll_view != NULL, RET_BAD_PARAMS);

    switch_enable = widget_get_prop_bool(&scroll_view->widget, PAGE_SWITCH_PROP_ENABLE, FALSE);
    if (!switch_enable) {
        return ret;
    }

    win = widget_get_window(page);
    return_value_if_fail(win != NULL, RET_BAD_PARAMS);
    view_menu = widget_lookup(win, "view_menu", TRUE);

    pages = page->parent;
    return_value_if_fail(pages != NULL, RET_BAD_PARAMS);

    old_index = new_index = widget_index_of(page);

    move_dy = scroll_view->down.y - pe->y;
    y = scroll_view->yoffset_save + move_dy;

    if (y < -PAGE_SWITCH_THRESHOLD) {
        new_index--;
    } else if (y + scroll_view->widget.h > scroll_view->virtual_h + PAGE_SWITCH_THRESHOLD) {
        new_index++;
    }
    new_index = tk_min(tk_max(0, new_index), PAGE_NUM - 1);

    if (new_index != old_index) {
        if (view_menu != NULL) {
            widget_t *new_page = widget_get_child(pages, new_index);
            if (new_page != NULL) {
                widget_t *tb = NULL;
                char tb_name[TK_NAME_LEN + 1] = {0};

                tk_snprintf(tb_name, ARRAY_SIZE(tb_name), "tb_%s", new_page->name + 5);
                tb = widget_lookup(view_menu, tb_name, TRUE);
                widget_set_value(tb, TRUE);
            }
        } else {
            pages_set_active(pages, new_index);
        }

        ret = RET_STOP;
    }

    widget_set_prop_bool(&scroll_view->widget, PAGE_SWITCH_PROP_ENABLE, FALSE);
    return ret;
}
#endif

static ret_t on_page_enter(void *ctx, event_t *e)
{
#if defined(ENABLE_PAGE_SWITCH) && ENABLE_PAGE_SWITCH
    widget_t *scroll_view = NULL;
#endif
    widget_t *page = WIDGET(e->target);
    page_enter_func_t enter_func = (page_enter_func_t)ctx;
    return_value_if_fail(page != NULL, RET_BAD_PARAMS);

    change_menu_title(widget_get_window(page), page);

    widget_foreach(page, fix_widget_size, page);

#if defined(ENABLE_PAGE_SWITCH) && ENABLE_PAGE_SWITCH
    scroll_view = widget_lookup_by_type(page, WIDGET_TYPE_SCROLL_VIEW, TRUE);
    if (scroll_view != NULL) {
        widget_on(scroll_view, EVT_POINTER_UP_BEFORE_CHILDREN, on_page_switch_before, page);
        widget_on(scroll_view, EVT_POINTER_UP, on_page_switch, page);
    }
#endif

    if (enter_func) {
        enter_func(page);
    }

    return RET_OK;
}

static ret_t on_menu_bar_open(void *ctx, event_t *e)
{
    widget_t *win = WIDGET(ctx);
    widget_t *top_win = window_manager_get_top_window(window_manager());
    widget_t *vpages = widget_lookup(win, "vpages", TRUE);

    return_value_if_fail(vpages != NULL, RET_BAD_PARAMS);

    if (!(top_win == win || widget_is_overlay(top_win))) {
        if (widget_is_dialog(top_win) && dialog_is_modal(top_win)) {
            dialog_quit(top_win, DIALOG_QUIT_CANCEL);
        } else {
            window_close(top_win);
        }
    }

    return open_menu_bar(vpages);
}

static ret_t adject_widget_in_1m_assets(void *ctx, const void *iter)
{
    widget_t *widget = WIDGET(iter);
    bool_t invisible_in_1m = widget_get_prop_bool(widget, WIDGET_PROP_INVISIBLE_IN_1M, FALSE);

    if (invisible_in_1m) {
        widget_set_visible(widget, FALSE);
        widget_set_sensitive(widget, FALSE);
    } else {
        bool_t disable_in_1m = widget_get_prop_bool(widget, WIDGET_PROP_DISABLE_IN_1M, FALSE);
        if (disable_in_1m) {
            widget_set_enable(widget, FALSE);
        }

        if (tk_str_eq(widget->name, "vpages")) {
            WIDGET_FOR_EACH_CHILD_BEGIN(widget, page, i)
            widget_on(page, EVT_VPAGE_WILL_OPEN, on_adject_vpage_in_1m_assets, NULL);
            WIDGET_FOR_EACH_CHILD_END()
        }
    }

    return RET_OK;
}

static ret_t on_adject_vpage_in_1m_assets(void *ctx, event_t *e)
{
    widget_t *vpage = WIDGET(e->target);
    return_value_if_fail(vpage != NULL, RET_BAD_PARAMS);
    return widget_foreach(vpage, adject_widget_in_1m_assets, NULL);
}

static ret_t on_adject_win_in_1m_assets(void *ctx, event_t *e)
{
    window_event_t *we = window_event_cast(e);
    return_value_if_fail(we != NULL, RET_BAD_PARAMS);

    return widget_foreach(we->window, adject_widget_in_1m_assets, NULL);
}

static bool_t check_is_use_1m_assets(void)
{
    const asset_info_t *res = assets_manager_ref(assets_manager(), ASSET_TYPE_IMAGE, "logo_dynamic");
    bool_t is_use_1m_assets = (res == NULL);

    if (res != NULL) {
        assets_manager_unref(assets_manager(), res);
    }

    return is_use_1m_assets;
}

static ret_t vpage_change_kb_type_without_zh(void *ctx, const void *iter)
{
    widget_t *widget = WIDGET(iter);
    const widget_vtable_t *vt = widget->vt;

    while (vt != NULL) {
        if (tk_str_eq(vt->type, WIDGET_TYPE_EDIT)) {
            edit_t *edit = EDIT(widget);
            if (edit != NULL && tk_str_eq(edit->keyboard, WINDOW_NAME_PREFIX "kb_default")) {
                edit_set_keyboard(widget, WINDOW_NAME_PREFIX "kb_ascii");
            }
            break;
        } else if (tk_str_eq(vt->type, WIDGET_TYPE_MLEDIT)) {
            mledit_t *mledit = MLEDIT(widget);
            if (mledit != NULL && tk_str_eq(mledit->keyboard, WINDOW_NAME_PREFIX "kb_default")) {
                mledit_set_keyboard(widget, WINDOW_NAME_PREFIX "kb_ascii");
            }
            break;
        }

        vt = (vt->get_parent_vt != NULL) ? vt->get_parent_vt() : NULL;
    }

    return RET_OK;
}

static ret_t on_vpage_change_kb_type_without_zh(void *ctx, event_t *e)
{
    widget_t *vpage = WIDGET(e->target);
    return_value_if_fail(vpage != NULL, RET_BAD_PARAMS);
    return widget_foreach(vpage, vpage_change_kb_type_without_zh, NULL);
}

static ret_t on_change_kb_type_without_zh(void *ctx, event_t *e)
{
    window_event_t *we = window_event_cast(e);
    return_value_if_fail(we != NULL && we->window != NULL, RET_BAD_PARAMS);

    WIDGET_FOR_EACH_CHILD_BEGIN(we->window, iter, i)
    if (tk_str_eq(iter->name, "vpages")) {
        WIDGET_FOR_EACH_CHILD_BEGIN(iter, page, i)
        widget_on(page, EVT_VPAGE_WILL_OPEN, on_vpage_change_kb_type_without_zh, NULL);
        WIDGET_FOR_EACH_CHILD_END()
    }
    WIDGET_FOR_EACH_CHILD_END()

    return RET_OK;
}

// 子控件初始化(主要是设置click回调、初始显示信息)
static ret_t init_widget(void* ctx, const void* iter)
{
    widget_t *widget = WIDGET(iter);
    widget_t *win = WIDGET(ctx);

    if (widget->name != NULL) {
        const char *name = widget->name;
        if (tk_str_eq(name, "rb_dark")) {
            widget_set_value(widget, tk_str_eq(assets_manager()->theme, "dark"));
            widget_on(widget, EVT_VALUE_CHANGED, on_change_theme, NULL);
        } else if (tk_str_eq(name, "rb_zh")) {
            if (s_is_full_font) {
                widget_set_value(widget, tk_str_eq(locale_info()->language, "zh"));
                widget_on(widget, EVT_VALUE_CHANGED, on_language_changed, NULL);
            } else {
                widget_set_value(widget, FALSE);
                widget_set_enable(widget->parent, FALSE);
            }
        } else if (tk_str_eq(name, "btn_menu_on")) {
            widget_on(widget, EVT_CLICK, on_menu_bar_open, win);
        } else if (tk_str_eq(name, "img_logo")) {
            widget_t *sys_bar = widget->parent;
            uint32_t x = sys_bar->w;
            WIDGET_FOR_EACH_CHILD_BEGIN(sys_bar, child, i)
            if (child != widget && !tk_str_eq(child->name, "btn_menu_on")) {
                x = tk_min(child->x, x);
            }
            WIDGET_FOR_EACH_CHILD_END()

            if (x < widget->x + widget->w) {
                widget_set_visible(widget, FALSE);
                widget_set_sensitive(widget, FALSE);
            }
        } else if (tk_str_eq(name, "vpages")) {
            WIDGET_FOR_EACH_CHILD_BEGIN(widget, page, i)
            widget_on(page, EVT_VPAGE_WILL_OPEN, on_page_enter, (void *)s_page_enter_func_array[i]);
            WIDGET_FOR_EACH_CHILD_END()
        }
    }

    return RET_OK;
}

// 初始化窗口上的子控件
static void init_children_widget(widget_t *widget, void *ctx)
{
    widget_foreach(widget, init_widget, ctx);
}

#if defined(PRELOAD_DURATION) && PRELOAD_DURATION > 0
static ret_t timer_preload(const timer_info_t *timer)
{
    char num_str[8] = {0};
    static uint32_t cur_time = 0;
    static uint32_t cur_item = 0;
    widget_t *win_preload = WIDGET(timer->ctx);
    widget_t *lb_info = widget_lookup(win_preload, "lb_info", TRUE);
    widget_t *lb_progress_c = widget_lookup(win_preload, "lb_progress_c", TRUE);
    widget_t *progress_circle = widget_lookup(lb_progress_c, "progress_circle", TRUE);
    uint32_t progress_value = cur_time * 10 * 100 / PRELOAD_DURATION;

    tk_snprintf(num_str, ARRAY_SIZE(num_str), "%u%%", progress_value / 10);
    if (progress_circle != NULL) {
        widget_set_value(progress_circle, progress_value);
    }
    widget_set_text_utf8(lb_progress_c, num_str);

    if (cur_time >= cur_item * PRELOAD_DURATION / ARRAY_SIZE(preload_info)) {
        char ani_str[128] = {0};
        tk_snprintf(ani_str, ARRAY_SIZE(ani_str), "opacity(duration=%d,yoyo_times=1,easing=sin_inout,from=0,to=255)", tk_max(PRELOAD_DURATION / ARRAY_SIZE(preload_info), 0));
        widget_set_tr_text(lb_info, preload_info[cur_item++]);
        widget_animator_create(lb_info, ani_str);
    }

    cur_time += timer->duration;

    if (cur_time >= PRELOAD_DURATION) {
        WIDGET_FOR_EACH_CHILD_BEGIN(window_manager(), root, i)
        if (root != win_preload) {
            widget_set_visible(root, TRUE);
        }
        WIDGET_FOR_EACH_CHILD_END()

        window_close(win_preload);
        return RET_REMOVE;
    }

    return RET_REPEAT;
}

static widget_t *show_preload_window(void)
{
    widget_t *preload = window_open_with_prefix(PRELOAD_NAME);
    widget_add_timer(preload, timer_preload, 20);

    return preload;
}
#endif

static bool_t get_portrait(uint32_t w, int32_t h)
{
    bool_t is_portrait = FALSE;
#ifdef WITH_LCD_PORTRAIT
    is_portrait = TRUE;
#elif WITH_LCD_LANDSCAPE
    is_portrait = (h <= LANDSCAPE_WIDTH_THRESHOLD) ? TRUE : FALSE;
#else
    is_portrait = (w <= LANDSCAPE_WIDTH_THRESHOLD || w < h) ? TRUE : FALSE;
#endif
    return is_portrait;
}

static ret_t set_win_name(void)
{
    bool_t is_portrait = FALSE;
    widget_t *wm = window_manager();
    return_value_if_fail(wm != NULL, RET_FAIL);

    is_portrait = get_portrait(wm->w, wm->h);
    if (is_portrait) {
        s_win_name = "menu_portrait";
        s_sysbar_name = "sysbar_portrait";
    } else {
        s_win_name = "menu_landscape";
        s_sysbar_name = "sysbar_landscape";
    }
    s_is_portrait = is_portrait;

    return RET_OK;
}

ret_t awtk_application_init(void)
{
    widget_t *win = NULL;
    widget_t *wm = window_manager();

    set_win_name();

    s_win_default_width = wm->w;
    s_win_default_height = wm->h;
    s_win_default_portrait = get_portrait(wm->w, wm->h);

    if (check_is_use_1m_assets()) {
        widget_on(window_manager(), EVT_WINDOW_WILL_OPEN, on_adject_win_in_1m_assets, NULL);
    }

#ifdef APP_DEFAULT_FONT
    if (tk_str_eq(APP_DEFAULT_FONT, "default_full")) {
        s_is_full_font = TRUE;
    }
#endif

    if (!s_is_full_font) {
        widget_on(window_manager(), EVT_WINDOW_WILL_OPEN, on_change_kb_type_without_zh, NULL);
    }

#ifdef APP_DEFAULT_LANGUAGE
    if (!tk_str_eq(APP_DEFAULT_LANGUAGE, "zh") && !tk_str_eq(APP_DEFAULT_LANGUAGE, "en")) {
        log_debug("not support language:%s!\n", APP_DEFAULT_LANGUAGE);
        change_language(FALSE);
    } else {
        change_language(s_is_full_font && tk_str_eq(APP_DEFAULT_LANGUAGE, "zh"));
    }
#else
    change_language(FALSE);
#endif

    s_page_enter_func_array[0] = page_button_init;
    s_page_enter_func_array[6] = page_slider_init;
    s_page_enter_func_array[8] = page_image_init;
    s_page_enter_func_array[12] = page_tab_ctrl_init;
    s_page_enter_func_array[13] = page_color_init;
    s_page_enter_func_array[14] = page_animate_init;
    s_page_enter_func_array[16] = page_chart_init;
    s_page_enter_func_array[17] = page_window_init;

    window_open_with_prefix(s_sysbar_name);
    win = window_open_with_prefix(s_win_name);

    WIDGET_FOR_EACH_CHILD_BEGIN(window_manager(), root, i)
    widget_set_visible_only(root, FALSE);
    init_children_widget(root, (void*)win);
    WIDGET_FOR_EACH_CHILD_END()

#if defined(PRELOAD_DURATION) && PRELOAD_DURATION > 0
    show_preload_window();
#endif

  return RET_OK;
}

ret_t awtk_application_exit(void)
{
    log_debug("application_exit\n");

    tk_mem_dump();
    return RET_OK;
}

int awtk_ui_demo_init(int argc, char *argv[])
{
    if (argc != 2) {
        printf("Usage: %s <assets_path>[project/entry/gui_demo/awtk]\n", argv[0]);
        return -1;
    }

    return awtk_application_enter(320, 480, APP_MOBILE, "awtk_gui", argv[1], "default");
}

int awtk_ui_demo_exit(void)
{
    return 0;
}
